"""
步骤条组件模块
提供了一个美观、可定制的步骤条组件，用于展示流程进度
"""
from PyQt5.QtCore import Qt, QSize, QRect, QPoint
from PyQt5.QtGui import QPainter, QColor, QFont, QPen, QFontMetrics, QBrush
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy

from component.theme import Theme


class Steps(QWidget):
    """
    步骤条组件
    
    提供了一个美观、可定制的步骤条，用于展示流程进度
    
    参数:
        parent: 父组件
        steps: 步骤列表，每个步骤是一个字典，包含title和description字段
        current: 当前步骤索引（从0开始）
        direction: 步骤条方向，可选值为 "horizontal"（水平）或 "vertical"（垂直）
        space: 步骤之间的间距
        active_color: 激活状态的颜色
        inactive_color: 未激活状态的颜色
        finished_color: 已完成状态的颜色
        align_center: 是否居中对齐（仅对水平方向有效）
        simple: 是否使用简洁模式（不显示描述文本）
        dot_size: 步骤点的大小
        line_width: 连接线的宽度
    """
    
    def __init__(self, parent=None, steps=None, current=0, direction="horizontal",
                 space=100, active_color=None, inactive_color=None, finished_color=None,
                 align_center=True, simple=False, dot_size=24, line_width=2):
        super().__init__(parent)
        
        # 属性初始化
        self._steps = steps or [{"title": f"步骤 {i+1}", "description": ""} for i in range(3)]
        self._current = max(0, min(current, len(self._steps) - 1))  # 确保索引在有效范围内
        self._direction = direction
        self._space = space
        self._align_center = align_center
        self._simple = simple
        self._dot_size = dot_size
        self._line_width = line_width
        
        # 设置颜色
        self._active_color = active_color or Theme.PRIMARY
        self._inactive_color = inactive_color or "#C0C4CC"
        self._finished_color = finished_color or Theme.SUCCESS
        
        # 创建步骤标签
        self._step_labels = []
        self._description_labels = []
        
        # 设置布局
        if self._direction == "horizontal":
            self._layout = QHBoxLayout(self)
            if self._align_center:
                self._layout.setAlignment(Qt.AlignCenter)
        else:
            self._layout = QVBoxLayout(self)
            self._layout.setAlignment(Qt.AlignLeft)
        
        self._layout.setContentsMargins(20, 20, 20, 20)
        self._layout.setSpacing(0)
        
        # 创建步骤标签
        self._create_step_labels()
        
        # 设置大小策略
        if self._direction == "horizontal":
            self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
            min_height = self._dot_size + 60  # 点大小 + 文本高度 + 边距
            if not self._simple:
                min_height += 40  # 添加描述文本的高度
            self.setMinimumHeight(min_height)
        else:
            self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
            # 增加垂直方向的最小宽度，确保有足够空间显示描述文本
            min_width = 200
            if not self._simple:
                # 如果不是简洁模式，增加宽度以容纳描述文本
                min_width = 300
            self.setMinimumWidth(min_width)
            
            # 设置垂直方向的最小高度
            if self._simple:
                min_height = len(self._steps) * self._space + 40  # 添加上下边距
            else:
                min_height = len(self._steps) * max(self._space, 120) + 40
            self.setMinimumHeight(min_height)
        
        # 设置背景透明
        self.setAttribute(Qt.WA_StyledBackground, True)
        self.setStyleSheet("background: transparent;")
    
    def _create_step_labels(self):
        """创建步骤标签"""
        # 清空现有标签
        for label in self._step_labels + self._description_labels:
            if label and label.parent() == self:
                label.setParent(None)
                label.deleteLater()
        
        self._step_labels = []
        self._description_labels = []
        
        # 创建新标签
        for i, step in enumerate(self._steps):
            # 创建标题标签
            title_label = QLabel(step["title"], self)
            title_label.setObjectName(f"step_title_{i}")
            
            # 根据方向设置对齐方式
            if self._direction == "horizontal":
                title_label.setAlignment(Qt.AlignCenter)
            else:
                title_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            
            # 设置标题样式
            if i < self._current:
                # 已完成步骤
                title_color = self._finished_color
            elif i == self._current:
                # 当前步骤
                title_color = self._active_color
            else:
                # 未完成步骤
                title_color = self._inactive_color
            
            title_label.setStyleSheet(f"""
                #step_title_{i} {{
                    color: {title_color};
                    font-size: 14px;
                    font-weight: bold;
                    margin-top: 8px;
                    margin-bottom: 4px;
                }}
            """)
            
            self._step_labels.append(title_label)
            
            # 创建描述标签（如果不是简洁模式）
            if not self._simple and step.get("description"):
                desc_label = QLabel(step["description"], self)
                desc_label.setObjectName(f"step_desc_{i}")
                
                # 根据方向设置对齐方式
                if self._direction == "horizontal":
                    desc_label.setAlignment(Qt.AlignCenter)
                else:
                    desc_label.setAlignment(Qt.AlignLeft | Qt.AlignTop)
                
                desc_label.setWordWrap(True)
                
                # 设置描述样式
                desc_label.setStyleSheet(f"""
                    #step_desc_{i} {{
                        color: {Theme.TEXT_SECONDARY};
                        font-size: 12px;
                        margin-bottom: 8px;
                    }}
                """)
                
                self._description_labels.append(desc_label)
            else:
                self._description_labels.append(None)
        
        # 不在布局中添加标签，而是在绘制时手动定位
    
    def paintEvent(self, event):
        """绘制步骤条"""
        super().paintEvent(event)
        
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        if self._direction == "horizontal":
            self._draw_horizontal_steps(painter)
        else:
            self._draw_vertical_steps(painter)
    
    def _draw_horizontal_steps(self, painter):
        """绘制水平步骤条"""
        rect = self.rect()
        
        # 计算步骤点的位置
        step_count = len(self._steps)
        if self._align_center:
            # 居中对齐
            total_width = (step_count - 1) * self._space
            start_x = (rect.width() - total_width) / 2
        else:
            # 左对齐
            start_x = 30
        
        # 绘制步骤点和连接线
        for i in range(step_count):
            x = start_x + i * self._space
            y = 30  # 顶部边距
            
            # 绘制连接线
            if i < step_count - 1:
                # 设置线条颜色
                if i < self._current:
                    # 已完成线条
                    line_color = self._finished_color
                else:
                    # 未完成线条
                    line_color = self._inactive_color
                
                painter.setPen(QPen(QColor(line_color), self._line_width))
                painter.drawLine(
                    int(x + self._dot_size / 2), int(y + self._dot_size / 2),
                    int(x + self._space - self._dot_size / 2), int(y + self._dot_size / 2)
                )
            
            # 绘制步骤点
            if i < self._current:
                # 已完成步骤
                bg_color = self._finished_color
                text_color = "#FFFFFF"
                text = "✓"  # 对勾符号
            elif i == self._current:
                # 当前步骤
                bg_color = self._active_color
                text_color = "#FFFFFF"
                text = str(i + 1)
            else:
                # 未完成步骤
                bg_color = "#FFFFFF"
                text_color = self._inactive_color
                text = str(i + 1)
            
            # 绘制圆点背景
            painter.setPen(QPen(QColor(bg_color), 1))
            painter.setBrush(QBrush(QColor(bg_color)))
            painter.drawEllipse(
                int(x), int(y),
                int(self._dot_size), int(self._dot_size)
            )
            
            # 绘制圆点文本
            painter.setPen(QColor(text_color))
            font = QFont()
            font.setPixelSize(14)
            font.setBold(True)
            painter.setFont(font)
            
            # 计算文本位置
            fm = QFontMetrics(font)
            text_width = fm.width(text)
            text_height = fm.height()
            
            painter.drawText(
                int(x + (self._dot_size - text_width) / 2),
                int(y + (self._dot_size + text_height) / 2 - 2),
                text
            )
            
            # 定位标题标签
            title_label = self._step_labels[i]
            title_width = title_label.sizeHint().width()
            title_height = title_label.sizeHint().height()
            
            title_x = int(x + (self._dot_size - title_width) / 2)
            title_y = int(y + self._dot_size + 5)
            
            title_label.setGeometry(title_x, title_y, title_width, title_height)
            title_label.show()
            
            # 定位描述标签
            if not self._simple and self._description_labels[i]:
                desc_label = self._description_labels[i]
                desc_width = min(150, desc_label.sizeHint().width())
                desc_height = desc_label.sizeHint().height()
                
                desc_x = int(x + (self._dot_size - desc_width) / 2)
                desc_y = int(title_y + title_height + 2)
                
                desc_label.setGeometry(desc_x, desc_y, desc_width, desc_height)
                desc_label.show()
    
    def _draw_vertical_steps(self, painter):
        """绘制垂直步骤条"""
        rect = self.rect()
        
        # 计算步骤点的位置
        step_count = len(self._steps)
        start_y = 30  # 顶部边距
        
        # 如果不是简洁模式，增加步骤之间的间距以容纳描述文本
        actual_space = self._space
        if not self._simple:
            actual_space = max(self._space, 120)  # 确保有足够空间显示描述文本
        
        # 绘制步骤点和连接线
        for i in range(step_count):
            x = 30  # 左侧边距
            y = start_y + i * actual_space
            
            # 绘制连接线
            if i < step_count - 1:
                # 设置线条颜色
                if i < self._current:
                    # 已完成线条
                    line_color = self._finished_color
                else:
                    # 未完成线条
                    line_color = self._inactive_color
                
                painter.setPen(QPen(QColor(line_color), self._line_width))
                painter.drawLine(
                    int(x + self._dot_size / 2), int(y + self._dot_size / 2),
                    int(x + self._dot_size / 2), int(y + actual_space - self._dot_size / 2)
                )
            
            # 绘制步骤点
            if i < self._current:
                # 已完成步骤
                bg_color = self._finished_color
                text_color = "#FFFFFF"
                text = "✓"  # 对勾符号
            elif i == self._current:
                # 当前步骤
                bg_color = self._active_color
                text_color = "#FFFFFF"
                text = str(i + 1)
            else:
                # 未完成步骤
                bg_color = "#FFFFFF"
                text_color = self._inactive_color
                text = str(i + 1)
            
            # 绘制圆点背景
            painter.setPen(QPen(QColor(bg_color), 1))
            painter.setBrush(QBrush(QColor(bg_color)))
            painter.drawEllipse(
                int(x), int(y),
                int(self._dot_size), int(self._dot_size)
            )
            
            # 绘制圆点文本
            painter.setPen(QColor(text_color))
            font = QFont()
            font.setPixelSize(14)
            font.setBold(True)
            painter.setFont(font)
            
            # 计算文本位置
            fm = QFontMetrics(font)
            text_width = fm.width(text)
            text_height = fm.height()
            
            painter.drawText(
                int(x + (self._dot_size - text_width) / 2),
                int(y + (self._dot_size + text_height) / 2 - 2),
                text
            )
            
            # 定位标题标签
            title_label = self._step_labels[i]
            title_width = title_label.sizeHint().width()
            title_height = title_label.sizeHint().height()
            
            title_x = int(x + self._dot_size + 10)
            title_y = int(y + (self._dot_size - title_height) / 2)
            
            # 确保标题标签有足够的宽度
            available_width = rect.width() - title_x - 20  # 减去右侧边距
            title_label.setGeometry(title_x, title_y, available_width, title_height)
            title_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            title_label.show()
            
            # 定位描述标签
            if not self._simple and self._description_labels[i]:
                desc_label = self._description_labels[i]
                
                # 使用与标题相同的宽度，但允许文本换行
                desc_x = int(title_x)
                desc_y = int(title_y + title_height + 5)  # 增加与标题的间距
                
                # 计算描述文本的高度，考虑到换行
                desc_label.setWordWrap(True)  # 确保文本可以换行
                desc_label.setFixedWidth(available_width)  # 设置固定宽度以便计算正确的高度
                desc_height = desc_label.heightForWidth(available_width)
                if desc_height < 20:  # 确保最小高度
                    desc_height = 20
                
                # 设置描述标签的几何形状
                desc_label.setGeometry(desc_x, desc_y, available_width, desc_height)
                desc_label.setAlignment(Qt.AlignLeft | Qt.AlignTop)
                desc_label.show()
    
    def sizeHint(self):
        """返回建议的大小"""
        if self._direction == "horizontal":
            width = len(self._steps) * self._space
            height = 100 if self._simple else 150
            return QSize(width, height)
        else:
            # 增加垂直方向的建议宽度
            width = 300 if not self._simple else 250
            
            # 计算垂直方向的高度，考虑到描述文本可能需要更多空间
            if self._simple:
                height = len(self._steps) * self._space
            else:
                # 如果不是简洁模式，确保每个步骤有足够的空间显示描述文本
                height = len(self._steps) * max(self._space, 120)
            
            return QSize(width, height)
    
    def set_current(self, current):
        """设置当前步骤"""
        if 0 <= current < len(self._steps):
            self._current = current
            self._create_step_labels()  # 更新标签样式
            self.update()  # 触发重绘
    
    def get_current(self):
        """获取当前步骤"""
        return self._current
    
    def set_steps(self, steps):
        """设置步骤列表"""
        self._steps = steps
        self._current = min(self._current, len(self._steps) - 1)  # 确保当前步骤索引有效
        self._create_step_labels()  # 更新标签
        self.update()  # 触发重绘
    
    def get_steps(self):
        """获取步骤列表"""
        return self._steps
    
    def next_step(self):
        """前进到下一步"""
        if self._current < len(self._steps) - 1:
            self._current += 1
            self._create_step_labels()  # 更新标签样式
            self.update()  # 触发重绘
            return True
        return False
    
    def prev_step(self):
        """返回上一步"""
        if self._current > 0:
            self._current -= 1
            self._create_step_labels()  # 更新标签样式
            self.update()  # 触发重绘
            return True
        return False
    
    def set_direction(self, direction):
        """设置步骤条方向"""
        if direction in ["horizontal", "vertical"] and direction != self._direction:
            self._direction = direction
            
            # 更新布局
            old_layout = self.layout()
            if old_layout:
                # 移除旧布局中的所有部件
                while old_layout.count():
                    item = old_layout.takeAt(0)
                    if item.widget():
                        item.widget().setParent(None)
            
            # 创建新布局
            if self._direction == "horizontal":
                self._layout = QHBoxLayout(self)
                if self._align_center:
                    self._layout.setAlignment(Qt.AlignCenter)
                self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
                min_height = self._dot_size + 60
                if not self._simple:
                    min_height += 40
                self.setMinimumHeight(min_height)
            else:
                self._layout = QVBoxLayout(self)
                self._layout.setAlignment(Qt.AlignLeft)
                self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
                min_width = 200
                if not self._simple:
                    min_width = 300
                self.setMinimumWidth(min_width)
                
                # 设置垂直方向的最小高度
                if self._simple:
                    min_height = len(self._steps) * self._space + 40  # 添加上下边距
                else:
                    min_height = len(self._steps) * max(self._space, 120) + 40
                self.setMinimumHeight(min_height)
            
            self._layout.setContentsMargins(20, 20, 20, 20)
            self._layout.setSpacing(0)
            
            # 更新标签
            self._create_step_labels()
            self.update()  # 触发重绘
    
    def set_active_color(self, color):
        """设置激活状态的颜色"""
        self._active_color = color
        self._create_step_labels()  # 更新标签样式
        self.update()  # 触发重绘
    
    def set_inactive_color(self, color):
        """设置未激活状态的颜色"""
        self._inactive_color = color
        self._create_step_labels()  # 更新标签样式
        self.update()  # 触发重绘
    
    def set_finished_color(self, color):
        """设置已完成状态的颜色"""
        self._finished_color = color
        self._create_step_labels()  # 更新标签样式
        self.update()  # 触发重绘
    
    def set_space(self, space):
        """设置步骤之间的间距"""
        self._space = space
        
        # 如果是垂直方向，更新最小高度
        if self._direction == "vertical":
            if self._simple:
                min_height = len(self._steps) * self._space + 40
            else:
                min_height = len(self._steps) * max(self._space, 120) + 40
            self.setMinimumHeight(min_height)
        
        self.update()  # 触发重绘
    
    def set_dot_size(self, size):
        """设置步骤点的大小"""
        self._dot_size = size
        self.update()  # 触发重绘
    
    def set_line_width(self, width):
        """设置连接线的宽度"""
        self._line_width = width
        self.update()  # 触发重绘
    
    def set_simple(self, simple):
        """设置是否使用简洁模式"""
        if self._simple == simple:
            return
            
        self._simple = simple
        
        # 更新最小高度/宽度
        if self._direction == "horizontal":
            min_height = self._dot_size + 60
            if not self._simple:
                min_height += 40
            self.setMinimumHeight(min_height)
        else:
            min_width = 200
            if not self._simple:
                min_width = 300
            self.setMinimumWidth(min_width)
            
            # 更新垂直方向的最小高度
            if self._simple:
                min_height = len(self._steps) * self._space + 40
            else:
                min_height = len(self._steps) * max(self._space, 120) + 40
            self.setMinimumHeight(min_height)
        
        self._create_step_labels()  # 更新标签
        self.update()  # 触发重绘 